﻿using System;
using System.Collections.Generic;

namespace Jeffrey.XThreading
{
    using System.Threading;

    public delegate void RunTarget();

    public static class XThreadPool
    {
        private static readonly Int32 MAX_NUM = 20;
        private static Object m_SyncRoot = new Object();

        static XThreadPool()
        {
            m_Initialized = false;
            m_XThreads    = new List<XThread>();
        }

        public static void Initialize()
        {
            if (!m_Initialized)
            {
                for (Int32 i = 0; i < MAX_NUM; i++)
                {
                    m_XThreads.Add(new XThread());
                    m_XThreads[i].m_Thread.Name = i.ToString();
                }
                m_Initialized = true;
            }
        }

        public static Boolean AssignNewTask(RunTarget rt)
        {
            if (rt == null)
                throw new ArgumentNullException("RunTarget");

            lock (m_SyncRoot)
            {
                foreach(XThread thread in m_XThreads)
                {
                    if ( thread.m_Thread.ThreadState == (ThreadState.Unstarted | ThreadState.Background ))
                    {
                        thread.m_Stop = false;
                        thread.m_Target = rt;
                        thread.m_Thread.Start(thread);
                        return true;
                    }
                    else if ( thread.m_PoolSuspend && 
                              !thread.m_PoolRunningSuspend &&
                              thread.m_Thread.ThreadState == (ThreadState.Suspended | ThreadState.Background)
                            )
                    {
                        thread.m_Stop = false;
                        thread.m_Target = rt;
                        thread.m_Thread.Resume();
                        return true;
                    }
                }
                return false;
            }
        }

        public static Boolean AssignNewTask(XThread xt)
        {
            return AssignNewTask(xt.m_Target);
        }

        public static void SuspendAll()
        {
            foreach (XThread thread in m_XThreads)
            {
                if ( !thread.m_Stop &&
                     !thread.m_PoolSuspend &&
                     !thread.m_PoolRunningSuspend &&
                     (thread.m_Thread.ThreadState == (ThreadState.Running|ThreadState.Background) || 
                      thread.m_Thread.ThreadState == (ThreadState.WaitSleepJoin|ThreadState.Background))
                   )
                {
                    thread.m_Thread.Suspend();
                    thread.m_PoolRunningSuspend = true;
                }
            }
        }

        public static void ResumeAll()
        {
            foreach (XThread thread in m_XThreads)
            {
                if ( !thread.m_Stop &&
                     !thread.m_PoolSuspend &&
                      thread.m_PoolRunningSuspend
                   )
                {
                    thread.m_Thread.Resume();
                    thread.m_PoolRunningSuspend = false;
                }
            }
        }

        public static void StopAll()
        {
            foreach (XThread xt in m_XThreads)
            {
                if (xt.m_Thread.IsAlive)
                {
                    xt.m_Stop = true;
                    if (xt.m_PoolSuspend)
                    {
                        xt.m_Thread.Resume();
                        xt.m_Thread.Join();
                    }
                    else
                    {
                        try
                        {
                            xt.m_Thread.Abort();
                            xt.m_Thread.Join();
                        }
                        catch (ThreadAbortException)
                        {
                            Thread.ResetAbort();
                        }
                    }
                }
            }
        }

        public static Int32 RunningCount
        {
            get { return m_Count; }
        }

        public static Int32 MaxNum
        {
            get { return MAX_NUM; }
        }

        internal static void Run(Object obj)
        {
            XThread XT = obj as XThread;

            while (!XT.m_Stop)
            {
                if (XT.m_Target != null)
                {
                    m_Count++;
                    XT.m_Target();
                    m_Count--;
                }

                XT.m_PoolSuspend = true;
                Thread.CurrentThread.Suspend();
                XT.m_PoolSuspend = false;
            }
        }

        private static Boolean       m_Initialized;
        private static Int32         m_Count;
        private static List<XThread> m_XThreads;
    }
}
